# coding = utf-8

import re
import sys
import os
import argparse

# code comment tool path/bin
CODE_COMMENT_TOOL = '/home/ligongming/wkspace/compiler/llvm-project-11.1.0.src/build/bin/code_comment'
# clang path/tool
CLANG_BIN = '/home/ligongming/wkspace/compiler/llvm-project-11.1.0.src/build/bin/clang++'
INCLUDE_PATH = [
    '/home/ligongming/wkspace/compiler/llvm-project-11.1.0.src/clang-tools-extra/code_comment/include/'
]
def comment_finder(text):
    '''
        gen comment from the given text(str)
    '''
    pattern = re.compile( r'//.*?$|/\*.*?\*/', re.DOTALL | re.MULTILINE)
    result = pattern.findall(text)
    return result

def format_comment(text):
    '''
        comment format
    '''
    while True:
        before_text = text
        for sk in [' ', '\t', '\n', '/', '*']:
            before_text = before_text.strip(sk)
        if text == before_text:
            return before_text
        text = before_text
    return text
        
def deal_comment(cmt_info):
    '''
        deal with comment
    '''
    cmt_text = ' '.join(cmt_info)
    cmt_text = cmt_text.strip()
    if cmt_text.startswith('//'):
        cmt_text = cmt_text[2:]
    elif cmt_text.startswith('/*'):
        cmt_text = cmt_text[2:-2]
    else:
        return cmt_info
    
    cmt_text = cmt_text.strip()
    cmt_text = format_comment(cmt_text)
    if cmt_text.startswith('#@'):
        return ['__fakeHelperFuncForCommentGen__(0, ' + cmt_text[2:] + ');\n']
    return cmt_info

def comment_convert(src_file, dst_file):
    '''
        gen comment from file
    '''
    all_info = list()
    with open(src_file, 'r') as fp:
        cmt_info = list()
        in_comment = False
        for line in fp:
            if in_comment:
                cmt_info.append(line)
                if line.strip().endswith('*/'):
                    in_comment = False
                    all_info += deal_comment(cmt_info)
            else:
                if line.strip().startswith('//'):
                    all_info += deal_comment([line])
                elif line.strip().startswith('/*'):
                    if line.strip().endswith('*/'):
                        all_info += deal_comment([line])
                    else:
                        cmt_info.append(line)
                        in_comment = True
                else:
                    all_info.append(line)

    with open(dst_file, 'w') as fp:
        all_info = ['#include \"fake_comment_func.h\"\n'] + all_info
        fp.writelines(all_info)

def gen_comment(src_files, out_file = None, threads = None):
    '''
        code comment gen flow
    '''
    # step 1: file duplicate/convert
    dst_files = list()
    for src in src_files:
        dst = os.path.abspath(src)
        if dst.endswith('.h'):
            dst = dst + '.tmp.h'
        elif dst.endswith('.cpp'):
            dst = dst + '.tmp.cpp'
        else:
            continue
        comment_convert(os.path.abspath(src), dst)
        dst_files.append(dst)
    
    # step 2: do code comment generation
    code_comment_tool = CODE_COMMENT_TOOL
    tool_parameters = []
    if out_file:
        tool_parameters = ['-output %s'%out_file]
    if threads:
        tool_parameters += ['-threads %s'%str(threads)]

    clang_bin = CLANG_BIN
    cc_parameters = ['-c']
    for ipath in INCLUDE_PATH:
        cc_parameters += ['-I%s'%ipath]

    tool_cmd = code_comment_tool + ' ' + ' '.join(dst_files + tool_parameters) 
    cc_cmd = clang_bin + ' ' + ' '.join(cc_parameters)

    total_cmd = ' -- '.join([tool_cmd, cc_cmd])
    print(total_cmd)
    os.system(total_cmd)

    # step 3: remove all tmp file
    for dst in dst_files:
        if os.path.exists(dst):
            os.remove(dst)
    
if __name__ == '__main__':
    usage = 'python3 %s -f [source_file_list] -o [output_file] -t [parallel_threads]'%__file__
    parser = argparse.ArgumentParser(usage=usage)
    parser.add_argument('-f', '--files', nargs='+', help='source files')
    parser.add_argument('-o', '--output', help='output file')
    parser.add_argument('-t', '--threads', help='parallel threads')
    
    args = parser.parse_args()
    gen_comment(args.files, args.output, args.threads)
